import Vue from 'vue';
import lodash from 'lodash';

/**
 * 在树形数据中查找指定节点
 * @param {Array} tree 树形数据
 * @param {Function} predicate 判断条件的函数
 * @param {string} childrenKey 子节点的键名，默认为'children'
 * @returns {Object|null} 找到的节点，未找到则返回null
 */
export function $findTreeNode(tree, predicate, childrenKey = 'children') {
	// 遍历每一个节点
	for (const node of tree) {
		// 如果当前节点满足条件，返回当前节点
		if (predicate(node)) return node;
		// 如果有子节点，递归查找子节点
		if (lodash.has(node, childrenKey) && lodash.isArray(node[childrenKey]) && node[childrenKey].length > 0) {
			const foundNode = $findTreeNode(node[childrenKey], predicate, childrenKey);
			if (foundNode) return foundNode;
		}
	}
	// 未找到节点
	return null;
}

/**
 * 将扁平数据转换为树形数据
 * @param {Array} tree 扁平数据数组，每个元素需包含id和parentId
 * @param {string} childrenKey 子节点的键名，默认为'children'
 * @returns {Array} 转换后的树形数据
 */
export function $treeToFlat(tree, childrenKey = 'children') {
	return lodash.reduce(tree, (result, item) => {
		// 将当前节点添加到结果数组
		result.push(lodash.omit(item, childrenKey));
		// 如果有子节点，递归处理并合并结果
		if (lodash.has(item, childrenKey) && lodash.isArray(item[childrenKey]) && item[childrenKey].length) {
			result.push(...$treeToFlat(item[childrenKey], childrenKey));
		}
		return result;
	}, []);
}

/**
 * 将扁平数据转换为树形数据
 * @param {Array} items - 扁平数据数组，每个元素需包含id和parentId
 * @param {string|number} rootParentId - 根节点的parentId值，默认为0
 * @returns {Array} 转换后的树形数据
 */
export function $flatToTree(items, rootParentId = 0) {
	// 首先创建一个以id为键的映射表，方便快速查找
	let itemMap = lodash.keyBy(items, 'id');
	// 遍历所有项，构建树形结构
	return lodash.filter(items, item => {
		// 找到当前项的父项
		let parent = itemMap[item.pid];
		if (parent) {
			// 如果存在父项，将当前项添加到父项的children数组中
			parent.children = parent.children || [];
			parent.children.push(item);
			return false; // 过滤掉非根节点，它们会通过父节点的children属性被包含
		}
		// 根节点的parentId应与指定的rootParentId匹配
		return item.pid == rootParentId;
	});
}

/**
 * 向树形数据中添加节点
 * @param {Array} tree 树形数据
 * @param {number} parentId 父节点ID
 * @param {Object} newNode 要添加的新节点
 * @param {string} childrenKey 子节点的键名，默认为'children'
 * @returns {Array} 新的树形数据
 */
export function $addNodeToTree(tree, parentId, newNode, childrenKey = 'children') {
	// 深拷贝原数据，避免修改原数据
	let newTree = lodash.cloneDeep(tree);
	// 递归查找并添加节点
	function findAndAdd(nodeList) {
		lodash.forEach(nodeList, (node) => {
			// 如果找到父节点，添加新节点
			if (node.id === parentId) {
				// 确保children数组存在
				if (!node[childrenKey]) {
					node[childrenKey] = [];
				}
				node[childrenKey].push(newNode);
				return false; // 退出循环
			}
			// 如果有子节点，递归查找
			if (node[childrenKey] && node[childrenKey].length > 0) {
				const found = findAndAdd(node[childrenKey]);
				if (found) return false; // 已找到并添加，退出循环
			}
		});
	}
	findAndAdd(newTree);
	return newTree;
}

/**
 * 使用Lodash删除树形数据中的指定节点
 * @param {Array} tree 树形数据
 * @param {*} nodeId 要删除的节点ID
 * @param {string} childrenKey 子节点的键名，默认为'children'
 * @returns {Array} 删除节点后的树形数据
 */
export function $removeTreeNode(tree, nodeId, childrenKey = 'children') {
	// 深拷贝原始数据，避免修改原数据
	const newTree = lodash.cloneDeep(tree);
	// 递归处理节点
	function processNodes(nodes) {
		// 过滤掉需要删除的节点
		const filtered = lodash.filter(nodes, node => !lodash.isEqual(node['id'], nodeId));
		// 对每个节点的子节点递归处理
		lodash.forEach(filtered, node => {
			if (lodash.has(node, childrenKey) && lodash.isArray(node[childrenKey])) {
				node[childrenKey] = processNodes(node[childrenKey]);
			}
		});
		return filtered;
	}
	return processNodes(newTree);
}

/**
 * 使用Lodash删除树形数据中的指定节点
 * @param {Array} tree 树形数据
 * @param {*} nodeId 要删除的节点ID
 * @param {Object} newNode 要修改的节点
 * @param {string} childrenKey 子节点的键名，默认为'children'
 * @returns {Array} 删除节点后的树形数据
 */
export function $updateTreeNode(tree, nodeId, newNode, childrenKey = 'children') {
	// 深拷贝原始数据，避免修改原数据
	const newTree = lodash.cloneDeep(tree);
	// 递归处理节点
	function processNodes(nodes) {
		// 遍历节点
		lodash.forEach(nodes, node => {
			// 如果找到目标节点，更新节点
			if (lodash.isEqual(node['id'], nodeId)) lodash.merge(node, newNode);
			// 如果有子节点，递归处理
			if (lodash.has(node, childrenKey) && lodash.isArray(node[childrenKey])) {
				node[childrenKey] = processNodes(node[childrenKey]);
			}
		});
		return nodes;
	}
	return processNodes(newTree);
}

/**
 * 移动树形数据中的节点
 * @param {Array} tree 原始树形数据
 * @param {string|number} sourceId 要移动的节点ID
 * @param {string|number} targetParentId 目标父节点ID
 * @param {string} childrenKey 子节点的键名，默认为'children'
 * @param {number} position 要插入的位置，-1表示插入到末尾
 * @returns {Array} 新的树形数据
 */
export function $moveTreeNode(tree, sourceId, targetParentId, childrenKey = 'children', position = 'end') {
	// 深拷贝避免修改原数据
	const newTree = lodash.cloneDeep(tree);
	const findNodeAndParent = (nodes, targetId, parent = null) => {
		for (const node of nodes) {
			if (node.id === targetId) {
				return { node, parent, index: nodes.indexOf(node) };
			}
			if (node[childrenKey] && node[childrenKey].length) {
				const result = findNodeAndParent(node[childrenKey], targetId, node);
				if (result) return result;
			}
		}
		return null;
	}
	// 找到源节点和它的父节点
	const sourceInfo = findNodeAndParent(newTree, sourceId);
	if (!sourceInfo) return newTree;

	// 找到目标父节点
	const targetParentInfo = findNodeAndParent(newTree, targetParentId);
	if (!targetParentInfo) return newTree;

	const { node: sourceNode, parent: sourceParent, index: sourceIndex } = sourceInfo;
	const { node: targetParent } = targetParentInfo;
	sourceParent ? lodash.pullAt(sourceParent[childrenKey], sourceIndex) : lodash.pullAt(newTree, sourceIndex);
	// 添加到目标位置
	if (!targetParent[childrenKey]) {
		targetParent[childrenKey] = [];
	}
	if (position === 'start') {
		targetParent[childrenKey].unshift(sourceNode);
	} else if (typeof position === 'number') {
		lodash.splice(targetParent[childrenKey], position, 0, sourceNode);
	} else {
		// 默认添加到末尾
		targetParent[childrenKey].push(sourceNode);
	}
	return newTree;
}

/**
 * 树形数据关键字筛选
 * @param {Array} tree 树形数据数组
 * @param {string} keyword 筛选关键字
 * @param {string} [labelKey='label'] 节点文本字段名
 * @param {string} [childrenKey='children'] 子节点字段名
 * @returns {Array} 筛选后的树形数据
 */
export function $filterTreeByKey(tree, keyword, labelKey = 'label', childrenKey = 'children') {
	// 如果没有关键字，返回原始树
	if (!keyword) return lodash.cloneDeep(tree);
	// 递归筛选节点
	return lodash.reduce(tree, (result, node) => {
		// 检查当前节点是否包含关键字
		let nodeHasKeyword = lodash.includes(lodash.toLower(lodash.get(node, labelKey, '')), lodash.toLower(keyword));
		// 递归筛选子节点
		let filteredChildren = $filterTreeByKey(lodash.get(node, childrenKey, []), keyword, labelKey, childrenKey);
		// 如果当前节点包含关键字，或者有符合条件的子节点，就保留该节点
		if (nodeHasKeyword || !lodash.isEmpty(filteredChildren)) {
			// 克隆节点，避免修改原始数据
			let newNode = lodash.cloneDeep(node);
			// 更新子节点为筛选后的结果
			lodash.set(newNode, childrenKey, filteredChildren);
			result.push(newNode);
		}
		return result;
	}, []);
}